<template>
  <!-- 多组件综合示例页：点、线、面、图片标注、模型、底图切换、鼠标坐标显示 -->
  <div class="page-wrap">
    <!-- 顶部工具栏：用于切换当前展示的示例功能 -->
    <div class="toolbar">
      <el-button-group>
        <el-button size="small" :type="active==='all'?'primary':'default'" @click="selectDemo('all')">全部</el-button>
        <el-button size="small" :type="active==='point'?'primary':'default'" @click="selectDemo('point')">点</el-button>
        <el-button size="small" :type="active==='polyline'?'primary':'default'" @click="selectDemo('polyline')">线</el-button>
        <el-button size="small" :type="active==='polygon'?'primary':'default'" @click="selectDemo('polygon')">面</el-button>
        <el-button size="small" :type="active==='billboard'?'primary':'default'" @click="selectDemo('billboard')">图片标注</el-button>
        <el-button size="small" :type="active==='model'?'primary':'default'" @click="selectDemo('model')">3D模型</el-button>
        <el-button size="small" :type="active==='imagery'?'primary':'default'" @click="selectDemo('imagery')">底图切换</el-button>
        <el-button size="small" :type="active==='mouse'?'primary':'default'" @click="selectDemo('mouse')">鼠标坐标</el-button>
      </el-button-group>
    </div>

    <!-- 通过模板 ref 获取 CesiumViewer 暴露的 getViewer() -->
    <CesiumViewer ref="viewerComp" :options="viewerOptions" :camera="camera" :homeZoomOutFactor="0.6">
      <template #entities>
        <!-- 按需显示控件/实体 -->
        <ImageryLayerControl v-if="active==='all' || active==='imagery'" />
        <MousePosition v-if="active==='all' || active==='mouse'" />

        <!-- 点 -->
        <PointEntity
          v-if="active==='all' || active==='point'"
          ref="pointComp"
          :position="{ lon: 116.397, lat: 39.909, height: 0 }"
          :pixelSize="12"
          color="#ff4d4f"
        />

        <!-- 线（复用之前的折线组件） -->
        <PolylineEntity
          v-if="active==='all' || active==='polyline'"
          ref="polylineComp"
          :positions="polyline"
          :width="4"
          :material="'#00e5ff'"
        />

        <!-- 面 -->
        <PolygonEntity
          v-if="active==='all' || active==='polygon'"
          ref="polygonComp"
          :positions="polygon"
          material="rgba(0,229,255,0.25)"
          outlineColor="#00e5ff"
        />

        <!-- 图片标注 -->
        <BillboardEntity
          v-if="active==='all' || active==='billboard'"
          ref="billboardComp"
          :position="{ lon: 121.47, lat: 31.23, height: 0 }"
          image="https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png"
          :scale="1.2"
        />

        <!-- 模型（使用Cesium官方小模型 URL 示例） -->
        <ModelEntity
          v-if="active==='all' || active==='model'"
          ref="modelComp"
          :position="{ lon: 113.2644, lat: 23.1291, height: 0 }"
          url="https://cesium.com/downloads/cesiumjs/releases/1.115/Apps/SampleData/models/CesiumMan/Cesium_Man.glb"
          :scale="1"
          :minimumPixelSize="64"
        />
      </template>
    </CesiumViewer>
  </div>
  
</template>

<script setup>
// 综合示例：演示多个可复用实体组件的用法（所有变量与静态数据均配中文注释）
// 组件：Cesium 容器与各实体组件
import CesiumViewer from "@/components/cesium/CesiumViewer.vue";
import PointEntity from "@/components/cesium/PointEntity.vue";
import PolylineEntity from "@/components/cesium/PolylineEntity.vue";
import PolygonEntity from "@/components/cesium/PolygonEntity.vue";
import BillboardEntity from "@/components/cesium/BillboardEntity.vue";
import ModelEntity from "@/components/cesium/ModelEntity.vue";
import ImageryLayerControl from "@/components/cesium/ImageryLayerControl.vue";
import MousePosition from "@/components/cesium/MousePosition.vue";

// Vue 与 Cesium 依赖
import { ref, nextTick, onMounted, onActivated } from "vue";
import * as Cesium from "cesium";

// 模板 ref：获取子组件 CesiumViewer 的实例，以便调用其暴露的 getViewer()
const viewerComp = ref(null); // 组件实例
const viewer = ref(null);     // Cesium.Viewer 实例（从 getViewer() 获取）
// 各实体组件的模板 ref，便于读取各自的 props.position 或数据
const pointComp = ref(null);
const polylineComp = ref(null);
const polygonComp = ref(null);
const billboardComp = ref(null);
const modelComp = ref(null);

/**
 * 对象：Viewer 的构造配置（演示用）
 * - animation：是否显示动画面板
 * - baseLayerPicker：是否显示底图切换器（此处关闭，改用自定义控件）
 * - geocoder：是否显示地名搜索
 * - timeline：是否显示时间轴
 * - fullscreenButton：是否显示全屏按钮
 * - sceneModePicker：是否显示 2D/3D 切换
 */
const viewerOptions = {
  animation: false,
  baseLayerPicker: false, // 设置为false避免访问Cesium Ion资源
  geocoder: false,
  timeline: false,
  fullscreenButton: true,
  sceneModePicker: true,
};

/**
 * 对象：初始相机参数（单位：度/米），进入页面后会先飞到整球视角
 * - lon：经度
 * - lat：纬度
 * - height：高度（相机到地心的距离近似）
 * - heading：偏航角
 * - pitch：俯仰角
 * - roll：翻滚角
 */
const camera = {
  lon: 104.195397,
  lat: 35.86166,
  height: 16000000,
  heading: 0,
  pitch: -45,
  roll: 0,
};

/**
 * 响应式变量：当前展示的功能类型
 * 可选值：all/point/polyline/polygon/billboard/model/imagery/mouse
 */
const active = ref("all");

/**
 * 方法：切换示例并飞行到对应视角
 * @param {string} key 示例类型
 */
function selectDemo(key) {
  active.value = key;
  nextTick(() => flyToDemo(key));
}

/**
 * 方法：根据示例类型飞到合适视角
 */
function flyToDemo(key) {
  // 确保已拿到 viewer 实例；首次可能需要从子组件暴露方法取一次
  if (!viewer.value && viewerComp.value && typeof viewerComp.value.getViewer === "function") {
    viewer.value = viewerComp.value.getViewer();
  }
  const v = viewer.value;
  if (!v) return;

  if (key === "point") {
    // 点示例：以点组件自身的坐标为中心，降低高度并加大俯仰角
    const p = pointComp.value;
    const pos = p && p.$props && p.$props.position ? p.$props.position : { lon: 116.397, lat: 39.909, height: 0 };
    focusOnPoint(v, pos, { height: 3000, heading: 0, pitch: -60, roll: 0, duration: 1.0 });
  } else if (key === "polyline") {
    // 线示例：取折线点列的中点（经纬平均）为中心，更符合视觉预期
    const pl = polylineComp.value;
    const list = (pl && pl.$props && Array.isArray(pl.$props.positions)) ? pl.$props.positions : polyline;
    const mid = list.length ? list[Math.floor(list.length / 2)] : { lon: 116.39, lat: 39.9, height: 0 };
    focusOnPoint(v, { lon: mid.lon, lat: mid.lat, height: mid.height || 0 }, { height: 4000, heading: 0, pitch: -60, roll: 0, duration: 1.0 });
  } else if (key === "polygon") {
    // 面示例：以面顶点的包围球“完整适配”视角，确保面整体完全可见
    const pg = polygonComp.value;
    const list = (pg && pg.$props && Array.isArray(pg.$props.positions)) ? pg.$props.positions : polygon;
    if (list.length) {
      // 1) 将经纬高数组转为笛卡尔坐标，计算包围球
      const pts = list.map((p) => Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0));
      const bs = Cesium.BoundingSphere.fromPoints(pts);
      // 2) 使用 flyToBoundingSphere 以合适的距离与俯仰角完整展示整个面
      const pitch = Cesium.Math.toRadians(-40); // 稍小俯仰，避免离得过近导致边缘裁切
      const range = bs.radius * 3;            // 距离按半径的倍数放大，确保留出边距
      viewer.value.camera.flyToBoundingSphere(bs, {
        duration: 1.0,
        offset: new Cesium.HeadingPitchRange(0, pitch, range),
      });
    } else {
      // 数据为空则退回整球
      flyToHome(v);
    }
  } else if (key === "billboard") {
    // 图片标注：以标注自身位置为中心
    const b = billboardComp.value;
    const pos = b && b.$props && b.$props.position ? b.$props.position : { lon: 121.47, lat: 31.23, height: 0 };
    focusOnPoint(v, pos, { height: 2500, heading: 0, pitch: -55, roll: 0, duration: 1.0 });
  } else if (key === "model") {
    // 模型：以模型自身位置为中心
    const m = modelComp.value; // 获取模型组件实例
    const pos = m && m.$props && m.$props.position
      ? m.$props.position
      : { lon: 113.2644, lat: 23.1291, height: 0 }; // 兜底默认
    focusOnPoint(v, pos, { height: 2500, heading: 0, pitch: -55, roll: 0, duration: 1.0 });
  } else {
    flyToHome(v);
  }
}

/**
 * 方法：飞到指定经纬高（单位：度/米），并可设置相机姿态（单位：度）
 */
function flyToPosition(v, lon, lat, height = 15000, headingDeg = 0, pitchDeg = -45, rollDeg = 0) {
  const destination = Cesium.Cartesian3.fromDegrees(lon, lat, height);
  v.camera.flyTo({
    destination,
    orientation: {
      heading: Cesium.Math.toRadians(headingDeg),
      pitch: Cesium.Math.toRadians(pitchDeg),
      roll: Cesium.Math.toRadians(rollDeg),
    },
    duration: 1.0,
  });
}

// 方法：围绕某个“点”为中心进行近距离观察（更贴地的相机姿态）
function focusOnPoint(v, point, view) {
  // 1) 计算目标点的笛卡尔坐标，便于后续 lookAt 精确指向
  const target = Cesium.Cartesian3.fromDegrees(point.lon, point.lat, point.height || 0);
  // 2) 相机飞行到目标点上空一定高度，并设置合适的姿态（更贴近地表）
  v.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(point.lon, point.lat, view.height || 3000),
    orientation: {
      heading: Cesium.Math.toRadians(view.heading ?? 0),
      pitch: Cesium.Math.toRadians(view.pitch ?? -60),
      roll: Cesium.Math.toRadians(view.roll ?? 0),
    },
    duration: view.duration ?? 1.0,
    complete: () => {
      // 3) 飞行完成后短暂 lookAt 锁定，确保相机以该点为中心
      try {
        v.camera.lookAt(
          target,
          new Cesium.HeadingPitchRange(
            Cesium.Math.toRadians(view.heading ?? 0),
            Cesium.Math.toRadians(view.pitch ?? -60),
            view.height || 3000
          )
        );
        // 4) 解除锁定，避免后续交互受限（保留当前位置与方向）
        v.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
      } catch (_) {}
      try { v.requestRender(); } catch (_) {}
    },
  });
}

/**
 * 方法：飞到完整地球（等同 Home 视角）
 */
function flyToHome(v) {
  try {
    v.scene.camera.flyHome(1.0);
  } catch (_) {
    const rectangle = Cesium.Rectangle.MAX_VALUE;
    v.scene.camera.flyTo({ destination: rectangle, duration: 1.0 });
  }
}

// 生命周期：页面加载完成后飞到完整地球视角，并获取 viewer 实例
onMounted(() => {
  nextTick(() => {
    if (viewerComp.value && typeof viewerComp.value.getViewer === "function") {
      viewer.value = viewerComp.value.getViewer();
    }
    const v = viewer.value;
    if (!v) return;
    requestAnimationFrame(() => {
      try { v.resize(); v.requestRender(); } catch (_) {}
      flyToHome(v);
    });
  });
});

// 生命周期：再次进入该路由时，确保相机回到地球且画布铺满
onActivated(() => {
  const v = viewer.value;
  if (!v) return;
  try { v.resize(); v.requestRender(); } catch (_) {}
  flyToHome(v);
});

/**
 * 方法：根据一组经纬高点包络并飞到合适视距
 */
function flyToPositions(v, posArr, scale = 1.2) {
  if (!posArr || posArr.length === 0) return;
  const points = posArr.map((p) => Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.height || 0));
  const bs = Cesium.BoundingSphere.fromPoints(points);
  v.camera.flyToBoundingSphere(bs, { duration: 1.0, offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-30), bs.radius * scale) });
}

/**
 * 数组：折线示例数据（静态模拟数据）
 */
const polyline = [
  { lon: 116.39, lat: 39.9, height: 0 }, // 北京
  { lon: 121.47, lat: 31.23, height: 0 }, // 上海
  { lon: 113.27, lat: 23.13, height: 0 }, // 广州
];

/**
 * 数组：多边形示例数据（静态模拟数据）
 */
const polygon = [
  { lon: 112.9388, lat: 28.2282, height: 0 }, // 长沙
  { lon: 114.3054, lat: 30.5931, height: 0 }, // 武汉
  { lon: 113.6254, lat: 34.7466, height: 0 }, // 郑州
];
</script>

<style scoped>
.page-wrap {
  position: relative;
  width: 100%;
  height: 100%;
}
.toolbar {
  position: absolute;
  right: 12px;
  top: 12px;
  z-index: 20;
  background: rgba(255, 255, 255, 0.9);
  padding: 6px 8px;
  border-radius: 6px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
}
</style>